﻿//========================================================= 
/**@file PBOC_CmdDriver.h
 * @brief PBOC应用命令
 * 
 * @date 2016-04-26   17:18:40
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_PBOC_CMDDRIVER_H_
#define _LIBZHOUYB_PBOC_CMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../pboc/pboc_app.h"
using namespace zhou_yb::application::pboc;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// PBOC IC卡命令驱动
class PBOC_CmdDriver : 
    public CommonCmdDriver, 
    public BaseDevAdapterBehavior<ITransceiveTrans>
{
protected:
    //----------------------------------------------------- 
    ByteBuilder _appData;
    ByteBuilder _amountData;
    ByteBuilder _authData;
    PBOC_v2_0_AppAdapter _icAdapter;
    //----------------------------------------------------- 
public:
    //----------------------------------------------------- 
    PBOC_CmdDriver() : CommonCmdDriver()
    {
        _errGetter.Add(_icAdapter);
        _logSetter.select(_icAdapter);

        InformationTABLE = PBOC_TransTable::INFORMATION;
        AmountTABLE = PBOC_TransTable::AMOUNT;
        DetailTABLE = PBOC_TransTable::DETAIL;
        TlvAnsConvert = NULL;

        _RegisteCMD(PBOC_CmdDriver, SetTABLE);
        _RegisteCMD(PBOC_CmdDriver, SetTlvConvert);
        _RegisteCMD(PBOC_CmdDriver, SetTLV);
        _RegisteCMD(PBOC_CmdDriver, SetAmountTLV);
        _RegisteCMD(PBOC_CmdDriver, SetRandom);
        _RegisteCMD(PBOC_CmdDriver, ParseToINFO);
        _RegisteCMD(PBOC_CmdDriver, ParseToTAG);
        _RegisteCMD(PBOC_CmdDriver, SetPSE);
        _RegisteCMD(PBOC_CmdDriver, FLAGtoTAG);

        _RegisteCMD(PBOC_CmdDriver, EnumAid);
        _RegisteCMD(PBOC_CmdDriver, SelectAid);
        _RegisteCMD(PBOC_CmdDriver, GPO);
        _RegisteCMD(PBOC_CmdDriver, GetDATA);
        _RegisteCMD(PBOC_CmdDriver, GetRecode);
        _RegisteCMD(PBOC_CmdDriver, ReadTAG);
        _RegisteCMD(PBOC_CmdDriver, ReadTLV);
        _RegisteCMD(PBOC_CmdDriver, ExternalAuthenticate);
        _RegisteCMD(PBOC_CmdDriver, GAC);
        _RegisteCMD(PBOC_CmdDriver, ExecuteScript);
        _RegisteCMD(PBOC_CmdDriver, GetSW);

        _RegisteCMD(PBOC_CmdDriver, GetCardNumber);
        _RegisteCMD(PBOC_CmdDriver, GetBalance);
        _RegisteCMD(PBOC_CmdDriver, GetInformation);
        _RegisteCMD(PBOC_CmdDriver, GenARQC);
        _RegisteCMD(PBOC_CmdDriver, RunARPC);
        _RegisteCMD(PBOC_CmdDriver, GetDetail);
        _RegisteCMD(PBOC_CmdDriver, GetAmtDetail);

        _RegisteExceptCMD(PBOC_CmdDriver);
        _RegisteAdapterCMD(PBOC_CmdDriver);
    }
    virtual ~PBOC_CmdDriver()
    {
        if(InformationTABLE != PBOC_TransTable::INFORMATION)
        {
            delete[] InformationTABLE;
            InformationTABLE = NULL;
        }
        if(AmountTABLE != PBOC_TransTable::AMOUNT)
        {
            delete[] AmountTABLE;
            AmountTABLE = NULL;
        }
        if(DetailTABLE != PBOC_TransTable::DETAIL)
        {
            delete[] DetailTABLE;
            DetailTABLE = NULL;
        }
    }
    //----------------------------------------------------- 
    LC_CMD_ADAPTER_INVOKE(ITransceiveTrans, _icAdapter);
    //----------------------------------------------------- 
    /**
     * @brief 将TLV标签转换为键和值
     * @date 2017-02-17 11:37
     * 
     * @param [in] tlv 需要转换的TLV标签
     * @param [out] arg 转换后的标签和数据 [5A]="卡号"
     * @param [in] TlvConvert [default:NULL] 格式化信息时的转换函数
     * 
     * @return size_t 转换的标签数
     */
    static size_t TlvToArguments(const ByteArray& tlv, IStringArguments& arg, 
        PbocTlvConverter::fpTlvAnsConvert TlvAnsConvert = NULL)
    {
        TlvElement tagElement = TlvElement::Parse(tlv);
        TlvElement subElement = tagElement.MoveNext();
        string sHeader;
        ByteBuilder tagVal(32);
        ByteBuilder sVal(32);
        PbocTlvConverter cvt(TlvAnsConvert);
        size_t count = 0;
        while(!subElement.IsEmpty())
        {
            sHeader = TlvConvert::ToHeaderAscii(subElement.GetHeader());
            tagVal.Clear();
            sVal.Clear();

            subElement.GetValue(tagVal);
            if(TlvAnsConvert == NULL)
            {
                ByteConvert::ToAscii(tagVal, sVal);
            }
            else
            {
                cvt.Parse(subElement.GetHeader(), tagVal, sVal);
            }
            arg.Put(sHeader, sVal.GetString());

            ++count;
        }
        return count;
    }
    /**
     * @brief 将TLV的标签头和长度转换到Arguments中
     * @date 2017-02-18 09:12
     * 
     * @param [in] tlv 需要转换的标签
     * @param [out] arg 转换后的数据
     */
    static size_t TlvNonValueToArguments(const ByteArray& tlv, IStringArguments& arg)
    {
        TlvElement tagElement = TlvElement::Parse(tlv, TlvElement::NonValue);
        TlvElement subElement = tagElement.MoveNext();
        string sHeader;
        size_t count = 0;
        while(!subElement.IsEmpty())
        {
            sHeader = TlvConvert::ToHeaderAscii(subElement.GetHeader());
            arg.Put(sHeader, ArgConvert::ToString(subElement.GetLength()));

            ++count;
        }
        return count;
    }
    /**
     * @brief 将ABCD标签标识的字符串转为IStringArguments存储
     * @date 2017-02-09 16:06
     * 
     * @param [in] info 需要转换的标签数据
     * @param [in] lenbyte 标签数据长度标识位的位数
     * @param [out] arg 转换后的参数
     */
    static size_t MsgToArguments(const ByteArray& info, uint lenbyte, IStringArguments& arg)
    {
        const char* ptr = info.GetString();
        const char* infoEOF = ptr + info.GetLength() - 1;
        size_t len = 0;
        size_t count = 0;

        string sTag;
        ByteBuilder sVal;
        while(ptr <= infoEOF)
        {
            sTag = "";
            sTag += (*ptr);

            len = PBOC_AppHelper::getLen(ptr + 1, lenbyte);

            ptr += 1;
            ptr += lenbyte;

            sVal.Clear();
            sVal.Append(ByteArray(ptr, len));

            ptr += len;

            ++count;
            arg.Put(sTag, sVal.GetString());
        }
        return count;
    }
    /**
     * @brief 将IStringArguments转换为标签格式的字符串
     * @date 2017-02-09 16:08
     * 
     * @param [in] arg 需要转换的参数
     * @warning 如果参数的键值长度超过1,则不作为标签添加
     *
     * @param [in] lenbyte 标签数据长度标识位的位数
     * @param [out] info 转换后的标签字符串
     */
    static size_t ArgumentsToMsg(IStringArguments& arg, uint lenbyte, ByteBuilder& info)
    {
        size_t count = 0;
        IStringArguments::EnumeratorType enumer = arg.GetEnumerator();
        ByteBuilder lenFormat(8);
        ByteBuilder lenBuff(8);

        lenFormat += "%0";
        lenFormat.Format("%d", lenbyte);
        lenFormat += "d";

        while(enumer.MoveNext())
        {
            string& sKey = enumer.Current().Key;
            if(sKey.length() != 1)
                continue;

            info += sKey[0];
            string& sVal = enumer.Current().Value;
            info.Format(lenFormat.GetString(), sVal.length());
            info.Append(ByteArray(sVal.c_str(), sVal.length()));
            ++count;
        }
        return count;
    }
    /**
     * @brief 合并标签(对于重复的标签设置新的值和长度,非重复标签添加)
     * @date 2017-03-08 00:17
     * 
     * @param [in] src 待合并的标签
     * @param [out] tlv 合并后的标签数据
     * 
     * @return size_t 新增加的标签数
     */
    static size_t MergeTLV(const ByteArray& src, const ByteArray& tlv, ByteBuilder& dst)
    {
        TlvElement srcRoot = TlvElement::Parse(src, TlvElement::Normal);

        TlvElement subElement = srcRoot.MoveNext();
        size_t count = 0;

        TlvEditor tlvRoot;
        TlvEditor::iterator itr;

        tlvRoot.Parse(tlv);
        while(!subElement.IsEmpty())
        {
            itr = tlvRoot.Element(tlvRoot.Root(), subElement.GetHeader());
            if(itr != tlvRoot.Root())
            {
                tlvRoot.SetTLV(itr, subElement.GetHeader(), subElement.GetValue());
            }
            else
            {
                // 新的标签
                tlvRoot.Insert(tlvRoot.Root(), subElement.GetHeader(), subElement.GetValue());
                ++count;
            }
            subElement = srcRoot.MoveNext();
        }
        tlvRoot.GetTLV(tlvRoot.Root(), dst);
        return count;
    }
    //----------------------------------------------------- 
    /* 相关属性 */
    /// 读取信息的对照表
    const ushort* InformationTABLE;
    /// 交易信息的对照表
    const ushort* AmountTABLE;
    /// 交易明细的对照表
    const ushort* DetailTABLE;
    /// TLV格式转换器
    PbocTlvConverter::fpTlvAnsConvert TlvAnsConvert;
    //----------------------------------------------------- 
    /* 属性设置 */
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(SetTABLE);
        EXCEPT_CMD(SetTlvConvert);
        EXCEPT_CMD(SetTLV);
        EXCEPT_CMD(ParseToINFO);
        EXCEPT_CMD(ParseToTAG);
        EXCEPT_CMD(SetAmountTLV);
        EXCEPT_CMD(SetRandom);
        EXCEPT_CMD(SetPSE);
        EXCEPT_CMD(FLAGtoTAG);
        return true;
    }
    /**
     * @brief 设置数据表
     * @date 2016-10-23 21:35
     * 
     * @param [in] TABLE : string 需要设置的表名称
     * - 表名:
     *  - Information
     *  - Amount
     *  - Detail
     * .
     * @param [in] TAG : string 单个的TAG值和对应的标签(A:5A)
     * 
     * @retval FLAG : string 返回识别到的标签
     */
    LC_CMD_METHOD(SetTABLE)
    {
        string name;
        if(!arg.Get("TABLE", name))
        {
            _logErr(DeviceError::ArgErr, "缺少字段[TABLE]");
            return false;
        }

        // 解析并生成表
        MapArguments<char, ushort> map;
        IStringArguments::EnumeratorType enumer = arg.GetEnumerator();
        while(enumer.MoveNext())
        {
            // Key 必须只为一个字符
            if(enumer.Current().Key.length() > 1)
                continue;
            char cKey = enumer.Current().Key[0];
            ushort tagVal = TlvConvert::ERROR_TAG_HEADER;
            TlvConvert::TransHeader(enumer.Current().Value.c_str(), tagVal);
            if(tagVal == TlvConvert::ERROR_TAG_HEADER)
                continue;

            if(!map.Contains(cKey))
            {
                map.Put(cKey, tagVal);
            }
            else
            {
                map[cKey].Value = tagVal;
            }
        }

        ushort* tmpTable = NULL;

        const ushort** pTable = NULL;
        const ushort* pDefaultTable = NULL;
        if(StringConvert::Compare(name.c_str(), "Information", true))
        {
            pTable = &InformationTABLE;
            pDefaultTable = PBOC_TransTable::INFORMATION;
        }
        else if(StringConvert::Compare(name.c_str(), "Amount", true))
        {
            pTable = &AmountTABLE;
            pDefaultTable = PBOC_TransTable::AMOUNT;
        }
        else if(StringConvert::Compare(name.c_str(), "Detail", true))
        {
            pTable = &DetailTABLE;
            pDefaultTable = PBOC_TransTable::DETAIL;
        }
        else
        {
            _logErr(DeviceError::ArgFormatErr, "TABLE错误");
            return false;
        }

        if((*pTable) != pDefaultTable)
        {
            delete[] pTable;
            pTable = NULL;
        }

        size_t tableSize = map.Count();
        // 恢复为默认
        if(tableSize < 1)
        {
            (*pTable) = pDefaultTable;
            tableSize = PBOC_AppHelper::getTableSize(pDefaultTable);
        }
        else
        {
            // 构造新表
            tmpTable = new ushort[2 * tableSize + 2];
            MapArguments<char, ushort>::EnumeratorType mapItr = map.GetEnumerator();
            for(size_t i = 0;i < tableSize; ++i)
            {
                if(!mapItr.MoveNext())
                    break;
                tmpTable[TABLE_L(i)] = mapItr.Current().Key;
                tmpTable[TABLE_R(i)] = mapItr.Current().Value;
            }
            tmpTable[TABLE_L(tableSize)] = 0;
            tmpTable[TABLE_R(tableSize)] = 0;

            (*pTable) = tmpTable;
        }
        // 组 FLAG
        string sFlag = "";
        for(size_t i = 0;i < tableSize; ++i)
        {
            sFlag += static_cast<char>((*pTable)[TABLE_L(i)]);
        }
        rlt.Put("FLAG", sFlag);
        return true;
    }
    /**
     * @brief 设置标签格式转换接口
     * @date 2017-02-11 15:18
     * 
     * @param [in] TlvConvert : pointer 转换TLV的字符集回调函数 PbocTlvConverter::fpTlvAnsConvert
     */
    LC_CMD_METHOD(SetTlvConvert)
    {
        string str;
        if(arg.Get("TlvConvert", str))
        {
            TlvAnsConvert = reinterpret_cast<PbocTlvConverter::fpTlvAnsConvert>(ArgConvert::FromString<pointer>(str));
        }
        return true;
    }
    //----------------------------------------------------- 
    /* PBOC应用子命令 */
    /**
     * @brief 设置PSE AID值
     * @param [in] AID : hex 需要设置的PSE值
     *
     * @retval AID : hex 设置前的PSE值
     */
    LC_CMD_METHOD(SetPSE)
    {
        rlt.Put("AID", ArgConvert::ToString(_icAdapter.PSE()));

        string sPse = arg["AID"].To<string>();
        _icAdapter.PSE().Clear();
        DevCommand::FromAscii(sPse.c_str(), _icAdapter.PSE());
        return true;
    }
    /**
     * @brief 设置TLV数据
     * @date 2016-06-21 19:32
     * 
     * @param [in] Name : string 需要设置的TLV名称
     * - 名称:
     *  - App 应用数据
     *  - Terminal 终端数据
     * .
     * @param [in] TLV : hex 需要设置的终端数据
     * @param [in] Mode : string [default:Merge] 设置模式
     * - 模式:
     *  - Merge 合并标签
     *  - Replace 清空后重新设置整个TLV数据
     *  - Append 增加新的终端数据
     * .
     * @param [in] IsExport : bool [default:false] 是否需要导出设置后的TLV数据
     * 
     * @retval TLV : hex 新的终端数据
     */
    LC_CMD_METHOD(SetTLV)
    {
        string sTlvName = arg["Name"].To<string>();
        ByteBuilder* pDst = NULL;
        if(StringConvert::Compare(sTlvName.c_str(), "App", true))
        {
            pDst = &_appData;
        }
        else if(StringConvert::Compare(sTlvName.c_str(), "Terminal", true))
        {
            pDst = &_icAdapter.TerminalValue;
        }
        else
        {
            _logErr(DeviceError::ArgErr, "TLV名称错误");
            return false;
        }

        string sTlv = arg["TLV"].To<string>();
        bool isExport = arg["IsExport"].To<bool>(false);

        ByteBuilder tlv(16);
        DevCommand::FromAscii(sTlv.c_str(), tlv);

        string sMode = arg["Mode"].To<string>("Merge");
        ByteArray mode(sMode.c_str(), sMode.length());
        if(StringConvert::Compare(mode, "Merge", true))
        {
            ByteBuilder buff(32);
            MergeTLV(tlv, *pDst, buff);
            buff.Swap(*pDst);
        }
        else if(StringConvert::Compare(mode, "Replace", true))
        {
            pDst->Clear();
            pDst->Append(tlv);
        }
        else if(StringConvert::Compare(mode, "Append", true))
        {
            pDst->Append(tlv);
        }
        if(isExport)
        {
            rlt.Put("TLV", ArgConvert::ToString(*pDst));
        }
        return true;
    }
    /**
     * @brief 转换交易数据
     * @date 2017-02-10 10:44
     *
     * @param [in] IsToTerminal : bool [default:false] 是否将数据保存到终端数据中使用
     * @warning GetInformation接口中只支持从TerminalValue获取数据,对于特定的交易,提供一种折中的方式处理
     *
     * @param [in] TransINFO : string 交易数据(PQRST格式)
     * @param [in] LengthByte : uint [default:3] 交易数据长度字节数
     *
     * @warning 组交易数据时,数据以TransINFO优先,没有则根据下列的子项去组
     *
     * @param [in] Amount : uint [default:0] 交易金额(分)
     * @param [in] OtherAmount : uint [default:0] 其他金额(分)
     * @param [in] AmountType : uint [default:0] 交易类型
     * @param [in] AmountCode : uint [default:156] 交易货币代码
     * @param [in] Date : string [default:Auto] 交易日期
     * @param [in] Time : string [default:Auto] 交易时间
     * @param [in] Name : string [default:""] 商户名称
     * 
     * @retval AmountTLV : hex 交易数据
     */
    LC_CMD_METHOD(SetAmountTLV)
    {
        string sTransInfo;

        _amountData.Clear();
        if(arg.Get("TransINFO", sTransInfo))
        {
            uint lengthByte = arg["LengthByte"].To<uint>(3);
            PBOC_AppHelper::transToTLV(sTransInfo.c_str(), lengthByte, _amountData, AmountTABLE);
        }
        else
        {
            uint amount = arg["Amount"].To<uint>(0);
            uint otherAmount = arg["OtherAmount"].To<uint>(0);
            byte amountType = _itobyte(arg["AmountType"].To<uint>(0));
            uint amountCode = arg["AmountCode"].To<uint>(156);
            string sDate;
            const char* pDate = NULL;
            if(arg.Get("Date", sDate))
                pDate = sDate.c_str();
            string sTime;
            const char* pTime = NULL;
            if(arg.Get("Time", sTime))
                pTime = sTime.c_str();

            string sName = arg["Name"].To<string>();
            PBOC_v2_0_AppAdapter::PackAmountData(_amountData, amount, otherAmount, amountType, 
                amountCode, sDate.c_str(), sTime.c_str(), sName.c_str());
        }
        bool isToTerminal = arg["IsToTerminal"].To<bool>(false);
        if(isToTerminal)
        {
            PBOC_Library::SetTLV(_amountData, _icAdapter.TerminalValue);
        }
        rlt.Put("AmountTLV", ArgConvert::ToString(_amountData));
        return true;
    }
    /**
     * @brief 重置终端的随机数
     * @date 2017-03-08 10:14
     * 
     * @param [in] Random : hex [default:Auto] 需要重置的随机数,没有该值则自动重置
     * 
     * @retval [out] Random : hex 重置后的随机数
     */
    LC_CMD_METHOD(SetRandom)
    {
        string sRandom;
        if(arg.Get("Random", sRandom))
        {
            ByteBuilder random(8);
            DevCommand::FromAscii(sRandom.c_str(), random);

            ByteBuilder randomTLV(8);
            TlvConvert::MakeTLV(0x9F37, random, randomTLV);
            PBOC_Library::SetTLV(randomTLV, _icAdapter.TerminalValue);
        }
        else
        {
            ByteArray random = _icAdapter.Random();
            sRandom = ArgConvert::ToString(random);
        }
        rlt.Put("Random", sRandom);
        return true;
    }
    /**
     * @brief 提取应用数据中的标签转换为卡片信息
     * @date 2016-11-11 23:42
     * 
     * @param [in] FLAG : string [default:ALL] 需要提取的标签
     * @param [in] LengthByte : uint [default:3] 长度位数
     * @param [in] IsFillEmpty : bool [default:false] 是否填充没有找到的空标签
     * 
     * @retval INFO : string 获取到的卡片信息 
     * @retval FLAG : string 以ABCD为标识的子标签数据
     * @retval Count : uint 获取到的标签数
     */
    LC_CMD_METHOD(ParseToINFO)
    {
        string flag = arg["FLAG"].To<string>("");
        uint lenbyte = arg["LengthByte"].To<uint>(3);
        bool isFillEmpty = arg["IsFillEmpty"].To<bool>(false);
        // 组数据
        ByteBuilder info(64);
        PbocTlvConverter tlvConverter(TlvAnsConvert);
        size_t count = PBOC_AppHelper::transFromTLV(_appData, info, lenbyte, flag.c_str(), InformationTABLE, tlvConverter, isFillEmpty);

        rlt.Put("INFO", info.GetString());
        rlt.Put("Count", ArgConvert::ToString(count));
        MsgToArguments(info, lenbyte, rlt);
        return true;
    }
    /**
     * @brief 提取应用数据中的指定标签
     * @date 2017-02-10 20:30
     * 
     * @param [in] TLV : hex [default:AppData] 提取标签的数据源
     * @warning 如果没有该字段则默认AppData里面提取 
     *
     * @param [in] TAG : hex [default:ALL] 需要提取的标签列表
     * @param [in] IsFormat : bool [default:false] 是否需要格式化数据
     * 
     * @retval TAG : hex 指定的标签
     * @retval Count : uint 获取到的标签数目
     */
    LC_CMD_METHOD(ParseToTAG)
    {
        bool isFormat = arg["IsFormat"].To<bool>(false);
        string sTag;
        bool isParseAll = true;
        ByteBuilder tagBuff(32);
        if(arg.Get("TAG", sTag))
        {
            isParseAll = false;
            DevCommand::FromAscii(sTag.c_str(), tagBuff);
        }

        const ByteBuilder* pTlv = &_appData;
        ByteBuilder tlvBuff(8);
        string sTlv;
        if(arg.Get("TLV", sTlv))
        {
            DevCommand::FromAscii(sTlv.c_str(), tlvBuff);
            pTlv = &tlvBuff;
        }

        TlvElement appElement = TlvElement::Parse(*pTlv);
        TlvElement tagElement = isParseAll ? appElement : TlvElement::Parse(tagBuff, TlvElement::HeaderOnly);
        TlvElement subElement = tagElement.MoveNext();
        TlvElement subAppElement;
        TlvHeader header;
        string sHeader;
        ByteBuilder sVal(16);
        ByteBuilder sValAscii(32);
        size_t count = 0;
        PbocTlvConverter tlvConverter(TlvAnsConvert);
        while(!subElement.IsEmpty())
        {
            header = subElement.GetHeader();
            sHeader = TlvConvert::ToHeaderAscii(header);
            subAppElement = isParseAll ? subElement : appElement.Select(header);
            if(!subAppElement.IsEmpty())
            {
                sVal.Clear();
                subAppElement.GetValue(sVal);

                sValAscii.Clear();
                if(isFormat)
                {
                    tlvConverter.Parse(header, sVal, sValAscii);
                }
                else
                {
                    ByteConvert::ToAscii(sVal, sValAscii);
                }
                rlt.Put(sHeader, sValAscii.GetString());

                ++count;
            }

            subElement = tagElement.MoveNext();
        }
        rlt.Put("Count", ArgConvert::ToString(count));
        return true;
    }
    /**
     * @brief 将ABCD的应用标签转换为卡片的TLV标签
     * @date 2017-12-26 10:24
     * 
     * @param [in] FLAG : string [default:""] 需要读取的应用标签
     * @param [in] IsToARG : bool [default:true] 是否直接修改ARG参数中的TAG,还是输出到RLT中
     *
     * @retval TAG : hex 转换后的IC卡TLV标签
     */
    LC_CMD_METHOD(FLAGtoTAG)
    {
        ByteBuilder tag(16);
        string sFlag;
        if(arg.Get("FLAG", sFlag))
        {
            PBOC_AppHelper::getTagHeader(sFlag.c_str(), InformationTABLE, tag);
        }
        string sTag = arg["TAG"].To<string>();
        PBOC_AppHelper::assertTagHeaderAscii(tag, sTag.c_str());
        ByteBuilder asciiTag(32);
        ByteConvert::ToAscii(tag, asciiTag);
        if(arg["IsToARG"].To<bool>(true))
        {
            StringArguments::Set(arg, "TAG", asciiTag.GetString());
        }
        rlt.Put("TAG", asciiTag.GetString());
        return true;
    }
    //----------------------------------------------------- 
    /**
     * @brief 枚举卡片应用列表
     * @date 2016-06-14 21:51
     * 
     * @param [in] AID : hex [default:PSE] 枚举的子应用列表
     * 
     * @retval AID : hex 枚举到的AID
     * @retval Name : string 枚举到的AID名称
     * @retval Priority : uint 优先级
     * @retval Count : size_t 枚举到的AID数目
     */
    LC_CMD_METHOD(EnumAid)
    {
        string sAid = arg["AID"].To<string>();
        list_t<PBOC_Library::AID> aidlist;
        if(!_icAdapter.EnumAid(DevCommand::FromAscii(sAid.c_str()), aidlist))
        {
            _logErr(DeviceError::OperatorErr, "枚举应用列表失败");
            return false;
        }

        list_t<PBOC_Library::AID>::iterator itr;
        ByteBuilder tmp(16);
        for(itr = aidlist.begin();itr != aidlist.end(); ++itr)
        {
            tmp.Clear();
            ByteConvert::ToAscii(itr->aid, tmp);
            rlt.Put("AID", tmp.GetString());

            tmp.Clear();
            if(TlvAnsConvert == NULL)
            {
                rlt.Put("Name", itr->name.GetString());
            }
            else
            {
                TlvAnsConvert(itr->name.GetString(), itr->name.GetLength(), tmp);
                rlt.Put("Name", tmp.GetString());
            }

            rlt.Put("Priority", ArgConvert::ToString<uint>(static_cast<uint>(itr->priority)));
        }
        rlt.Put("Count", ArgConvert::ToString(aidlist.size()));
        return true;
    }
    /**
     * @brief 选择指定的应用
     * @date 2016-11-11 22:34
     * 
     * @param [in] AID : hex 需要选择的应用(支持多个应用)
     * @param [in] IsAllowLocked : bool [default:true] 是否需要支持被锁定的应用
     * 
     * @retval AID : hex 实际选择的AID完整名称
     * @retval AidData : hex 选择应用时返回的数据
     * @retval IsLocked : bool 当前应用是否被锁定
     */
    LC_CMD_METHOD(SelectAid)
    {
        list_t<PBOC_Library::AID> aidlist;
        list_t<string> sAidList;
        arg.Get("AID", sAidList);
        list_t<string>::iterator itr;
        for(itr = sAidList.begin();itr != sAidList.end(); ++itr)
        {
            aidlist.push_back();
            DevCommand::FromAscii(itr->c_str(), aidlist.back().aid);
        }
        // 如果AID为空则采用默认的AID进行操作
        if(aidlist.size() < 1)
        {
            // PSE
            aidlist.push_back();
            // A000000333
            aidlist.push_back();
            DevCommand::FromAscii(PBOC_V2_0_BASE_AID, aidlist.back().aid);
        }
        ByteBuilder aidBuff(16);
        ByteBuilder fullAid(8);
        bool allowLocked = arg["IsAllowLocked"].To<bool>(true);
        if(!_icAdapter.SelectAid(aidlist, &aidBuff, &fullAid, allowLocked))
        {
            _logErr(DeviceError::OperatorErr, "选择应用失败");
            return false;
        }

        ushort sw = ICCardLibrary::GetSW(aidBuff);
        ICCardLibrary::RemoveSW(aidBuff);

        bool isLocked = (sw == ICCardLibrary::SelectedFileNotVaild);
        rlt.Put("AID", ArgConvert::ToString(fullAid));
        rlt.Put("AidData", ArgConvert::ToString(aidBuff));
        rlt.Put("IsLocked", ArgConvert::ToString(isLocked));
        return true;
    }
    /**
     * @brief GPO生成应用数据
     * @date 2016-11-11 23:10
     * 
     * @param [in] AidData : hex 选应用时返回的数据
     * 
     * @retval GPO_Token : hex GPO数据
     * @retval DOL : hex 生成的DOL数据
     */
    LC_CMD_METHOD(GPO)
    {
        string sAidData = arg["AidData"].To<string>();
        ByteBuilder aidData(16);
        PBOC_Library::GPO_Token gpoToken;
        ByteBuilder dol(16);
        DevCommand::FromAscii(sAidData.c_str(), aidData);
        if(!_icAdapter.GPO(aidData, gpoToken, &dol))
        {
            _logErr(DeviceError::OperatorErr, "GPO失败");
            return false;
        }
        ByteBuilder gpoTag(32);
        PBOC_Library::GPO_TokenToTag(gpoToken, gpoTag);
        rlt.Put("GPO_Token", ArgConvert::ToString(gpoTag));
        rlt.Put("DOL", ArgConvert::ToString(dol));
        return true;
    }
    /**
     * @brief 获取GET DATA标签
     * @date 2017-08-20 11:39
     * 
     * @param [in] TAG : hex 需要获取的标签
     * 
     * @retval TLV : hex 获取到的全部数据
     * @retval Count : size_t 获取到的全部标签数目
     */
    LC_CMD_METHOD(GetDATA)
    {
        ByteBuilder appData(64);
        string sTag = arg["TAG"].To<string>("");
        list_t<TlvHeader> taglist;
        PBOC_Library::MakeTagList(sTag.c_str(), taglist);
        if(taglist.size() < 1)
        {
            _logErr(DeviceError::ArgCountErr, "没有需要查找的标签");
            return false;
        }
        size_t count = 0;
        if(!_icAdapter.GetDataTagValue(taglist, appData, &count))
            return false;
        ByteBuilder buff(64);
        ByteConvert::ToAscii(appData, buff);
        rlt.Put("TLV", buff.GetString());
        rlt.Put("Count", ArgConvert::ToString(count));
        return true;
    }
    /**
     * @brief 读记录获取标签
     * @date 2018-01-15 21:11
     *
     * @param [in] GPO_Token : hex GPO命令返回的数据
     * @param [in] TAG : hex [default:ALL] 需要读取的IC卡标签,空则读取所有IC卡数据
     * @param [in] SubTAG : hex [default:""] 获取的可选标签(如果获取TAG时有则获取,TAG查找完后不再查找没有找到的SubTAG)
     */
    LC_CMD_METHOD(GetRecode)
    {
        string sGpoToken = arg["GPO_Token"].To<string>();
        ByteBuilder tokenHex(8);
        ByteConvert::FromAscii(sGpoToken.c_str(), tokenHex);
        GPO_Token gpoToken;
        PBOC_Library::TagToGPO_Token(tokenHex, gpoToken);

        _appData.Clear();
        _authData.Clear();

        string sTag;
        if(!arg.Get("TAG", sTag))
        {
            if(!_icAdapter.GetAllAppData(gpoToken, _appData, &_authData))
            {
                _logErr(DeviceError::OperatorErr, "GPO获取应用数据失败");
                return false;
            }
        }
        else
        {
            ByteBuilder tag(16);
            DevCommand::FromAscii(sTag.c_str(), tag);

            list_t<TlvHeader> taglist;
            PBOC_Library::MakeTagList(tag, taglist);

            list_t<TlvHeader> subtagList;
            sTag = arg["SubTAG"].To<string>();
            tag.Clear();
            DevCommand::FromAscii(sTag.c_str(), tag);
            PBOC_Library::MakeTagList(tag, subtagList);

            if(!_icAdapter.GetSubAppData(gpoToken, taglist, subtagList, _appData))
            {
                _logErr(DeviceError::OperatorErr, "GPO获取标签数据失败");
                return false;
            }
        }
        return true;
    }
    /**
     * @brief 读取IC卡标签并保存到应用数据中(包括数据标签和记录标签)
     * @date 2016-05-06 18:06
     * 
     * @param [in] GPO_Token : hex GPO命令返回的数据
     * @param [in] TAG : hex [default:ALL] 需要读取的IC卡标签
     * @param [in] SubTAG : hex [default:""] 获取的可选标签
     */
    LC_CMD_METHOD(ReadTAG)
    {
        string sTag = arg["TAG"].To<string>();
        
        ByteBuilder tag(16);
        DevCommand::FromAscii(sTag.c_str(), tag);

        list_t<TlvHeader> taglist;
        PBOC_Library::MakeTagList(tag, taglist);
        if(taglist.size() < 1)
        {
            _logErr(DeviceError::ArgIsNullErr, "缺少需要读取的标签");
            return false;
        }
        list_t<TlvHeader> dataTagList;
        list_t<TlvHeader>::iterator itr;
        for(itr = taglist.begin();itr != taglist.end(); ++itr)
        {
            if(PBOC_Library::IsGetDataTag(*itr))
            {
                dataTagList.push_back(*itr);
                itr = list_helper<TlvHeader>::erase(taglist, itr);
            }
        }
        size_t count = 0;
         _appData.Clear();
        if(!_icAdapter.GetDataTagValue(dataTagList, _appData, &count))
            return false;

        string sGpoToken = arg["GPO_Token"].To<string>();
        ByteBuilder tokenHex(8);
        ByteConvert::FromAscii(sGpoToken.c_str(), tokenHex);
        GPO_Token gpoToken;
        PBOC_Library::TagToGPO_Token(tokenHex, gpoToken);

        dataTagList.clear();
        count += PBOC_Library::SelectTagToBuffer(taglist, tokenHex, _appData, &dataTagList);
        if(count >= taglist.size())
            return true;

        list_t<TlvHeader> subtagList;
        sTag = arg["SubTAG"].To<string>();
        tag.Clear();
        DevCommand::FromAscii(sTag.c_str(), tag);
        PBOC_Library::MakeTagList(tag, subtagList);
        list_helper<TlvHeader>::split(taglist, dataTagList);
        if(!_icAdapter.GetSubAppData(gpoToken, taglist, subtagList, _appData))
        {
            _logErr(DeviceError::OperatorErr, "GPO获取标签数据失败");
            return false;
        }
        return true;
    }
    /**
     * @brief 获取IC卡标签
     * @date 2016-05-06 18:15
     * 
     * @param [in] TAG : hex 需要获取的IC卡标签
     * @param [in] SubTAG : hex [default:""] 需要获取的可选标签
     * 
     * @retval TLV : hex 获取到的标签数据
     * @retval Count : uint 实际获取到的标签数
     */
    LC_CMD_METHOD(ReadTLV)
    {

        return true;
    }
    /**
     * @brief 外部认证
     * @date 2017-02-16 15:36
     * 
     * @param [in] ARPC : hex 需要验证的ARPC
     * - 格式:
     *  - TLV
     *  - 8字节认证数据
     *  - 8字节认证数据+2字节授权响应码
     * .
     */
    LC_CMD_METHOD(ExternalAuthenticate)
    {
        string sArpc;
        if(!arg.Get("ARPC", sArpc))
            return true;

        // 检查是否包含标签
        ByteBuilder arpc(8);
        DevCommand::FromAscii(sArpc.c_str(), arpc);

        TlvElement tagElement = TlvElement::Parse(arpc);
        ByteBuilder authArpc(8);
        ByteBuilder authCode(2);
        if(!PBOC_v2_0_StepAdapter::GetAuthCode(tagElement, authArpc, authCode))
            return true;

        ASSERT_FuncErrInfo(authArpc.GetLength() >= 8, DeviceError::ArgLengthErr, "外部认证数据格式错误");
        return _icAdapter.ExternalAuthenticate(authArpc, authCode);
    }
    /**
     * @brief 执行GAC
     * @date 2017-10-16 22:01
     *
     * @param [in] HEAD : hex [default:8C] 需要查找的GAC标签(8C/8D)
     * @param [in] TAG : hex [default:Null] 需要组55域的标签头,默认为标准标签,为Null时不输出55域数据
     * @param [in] IsFillEmpty : bool [default:false] 是否自动填充未找到标签的55域数据
     * @param [in] TLV : hex [default:Null] 需要查找的外部数据
     * @param [in] GAC_FLAG : string [default:Null] 需要生成的GAC类型(无参数时自动识别,8C为ARQC,8D为TC)
     * - GAC类型:
     *  - ARQC
     *  - TC
     *  - AAC
     *  - Reserve
     * .
     * 
     * @retval DOL : hex 生成的DOL数据
     * @retval GAC : hex 生成的GAC原始数据
     * @retval GAC_FLAG : string 实际生成的GAC类型
     * @retval TLV : hex 生成的55域报文
     */
    LC_CMD_METHOD(GAC)
    {
        byte gacTag = arg["HEAD"].To<byte>(0x8C);
        string sGacMode = arg["GAC_FLAG"].To<string>(gacTag == 0x8D ? "TC" : "ARQC");
        string sTlv = arg["TLV"].To<string>();

        GenerateACCmd::RefCtlFlag gacMode = GenerateACCmd::ARQC;
        ByteArray sGac(sGacMode.c_str(), sGacMode.length());
        if(StringConvert::Compare(sGac, "ARQC", true))
        {
            gacMode = GenerateACCmd::ARQC;
        }
        else if(StringConvert::Compare(sGac, "TC", true))
        {
            gacMode = GenerateACCmd::TC;
        }
        else if(StringConvert::Compare(sGac, "AAC", true))
        {
            gacMode = GenerateACCmd::AAC;
        }
        else if(StringConvert::Compare(sGac, "Reserve", true))
        {
            gacMode = GenerateACCmd::Reserve;
        }
        else
        {
            _logErr(DeviceError::ArgFormatErr, "GAC_FLAG错误");
            return false;
        }

        ByteBuilder tlvBuff(8);
        DevCommand::FromAscii(sTlv.c_str(), tlvBuff);

        TlvElement root = TlvElement::Parse(tlvBuff);
        TlvElement::Parse(root, _amountData);
        TlvElement::Parse(root, _icAdapter.TerminalValue);
        TlvElement::Parse(root, _appData);

        TlvHeader dolTag = gacTag;
        ByteBuilder gacData(64);
        ByteBuilder gacDol(64);
        GenerateACCmd::RefCtlFlag realGacMode = GenerateACCmd::Reserve;
        if(!_icAdapter.GAC(dolTag, gacMode, root, gacData, &realGacMode, &gacDol))
            return false;

        ByteBuilder buff(32);
        ByteConvert::ToAscii(gacDol, buff);
        rlt.Put("DOL", buff.GetString());

        buff.Clear();
        ByteConvert::ToAscii(gacDol, buff);
        rlt.Put("GAC", buff.GetString());

        sGacMode = "";
        switch(realGacMode)
        {
        case GenerateACCmd::ARQC:
            sGacMode = "ARQC";
            break;
        case GenerateACCmd::TC:
            sGacMode = "TC";
            break;
        case GenerateACCmd::AAC:
            sGacMode = "AAC";
            break;
        case GenerateACCmd::Reserve:
            sGacMode = "Reserve";
            break;
        }
        rlt.Put("GAC_FLAG", sGacMode);

        string sTag = "";
        if(!arg.Get("TAG", sTag))
            return true;

        bool isFillEmpty = arg["IsFillEmpty"].To<bool>(false);
        ByteBuilder gacArea(64);
        list_t<TlvHeader> taglist;
        const char* pTag = PBOC_V2_0_DEFAULT_TC_TAGLIST;
        if(sTag.length() > 0)
        {
            pTag = sTag.c_str();
        }
        PBOC_Library::MakeTagList(pTag, taglist);
        _icAdapter.PackGacArea(gacData, taglist, root, gacArea, isFillEmpty);

        buff.Clear();
        ByteConvert::ToAscii(gacArea, buff);
        rlt.Put("TLV", buff.GetString());
        return true;
    }
    /**
     * @brief 执行写卡脚本
     * @date 2017-02-16 15:51
     * 
     * @param [in] Script : hex 需要执行的TLV脚本标签
     * 
     * @retval ErrorIndex : size_t 失败时的错误脚本序号
     */
    LC_CMD_METHOD(ExecuteScript)
    {
        string sTLV = arg["Script"].To<string>();
        ByteBuilder script(32);
        DevCommand::FromAscii(sTLV.c_str(), script);
        TlvElement tagElement = TlvElement::Parse(script);
        ASSERT_FuncErrInfo(!tagElement.IsEmpty(), DeviceError::ArgFormatErr, "脚本TLV格式错误");

        size_t errIndex = 0;
        if(_icAdapter.ExecuteScript(tagElement, &errIndex))
            return true;
        rlt.Put("ErrorIndex", ArgConvert::ToString(errIndex));
        return false;
    }
    /**
     * @brief 获取上次操作的SW
     * @date 2017-02-16 15:38
     * 
     * @retval SW : hex 状态码
     * @retval MSG : string SW错误信息
     */
    LC_CMD_METHOD(GetSW)
    {
        ushort sw = _icAdapter.GetSW();
        rlt.Put("SW", _hex(sw, 2 * sizeof(char)));
        rlt.Put("MSG", ICCardLibrary::GetSW_MSG(sw));
        return true;
    }
    //----------------------------------------------------- 
    /* PBOC APP命令 */
    /**
     * @brief 
     * @date 2016-06-11 22:01
     * 
     * @param [in] AID : hex [default:PBOC] 需要获取的AID
     * @param [in] IsRootAID : bool [default:false] 是否为需要枚举子应用的根AID
     * @param [in] IsAllowLocked : bool [default:true] 是否允许读取被锁定的卡片
     * 
     * @retval CardNumber : string 获取到的卡号
     */
    LC_CMD_METHOD(GetCardNumber)
    {
        string sAid = arg["AID"].To<string>();
        bool isRootAid = arg["IsRootAID"].To<bool>(false);
        bool isAllowLocked = arg["IsAllowLocked"].To<bool>(true);

        ByteBuilder aid(8);
        DevCommand::FromAscii(sAid.c_str(), aid);

        // 枚举应用列表
        list_t<PBOC_Library::AID> aidlist;
        if(isRootAid)
        {
            if(!_icAdapter.EnumAid(aid, aidlist))
            {
                _logErr(DeviceError::OperatorErr, "PSE枚举应用列表失败");
                return false;
            }
        }
        else
        {
            if(aid.IsEmpty())
            {
                DevCommand::FromAscii(SYS_PBOC_V2_0_BASE_AID, aid);
            }

            aidlist.push_back();
            aidlist.back().aid = aid;
        }

        ByteBuilder cardNumber(8);
        list_t<PBOC_Library::AID>::iterator itr;
        for(itr = aidlist.begin();itr != aidlist.end(); ++itr)
        {
            if(_icAdapter.GetCardNumber(cardNumber, isAllowLocked, itr->aid))
                break;
        }
        if(itr == aidlist.end())
        {
            _logErr(DeviceError::OperatorErr, "应用列表获取卡号失败");
            return false;
        }

        rlt.Put("CardNumber", cardNumber.GetString());
        return true;
    }
    /**
     * @brief 获取卡片余额
     * @date 2016-06-21 18:00
     * 
     * @param [in] AID : hex [default:PBOC] 需要获取余额的AID
     * 
     * @retval Balance : uint 余额(以分为单位)
     */
    LC_CMD_METHOD(GetBalance)
    {
        string sAid = arg["AID"].To<string>();
        uint balance = 0;
        ByteBuilder aid(8);
        DevCommand::FromAscii(sAid.c_str(), aid);
        if(!_icAdapter.GetBalance(balance, aid))
        {
            _logErr(DeviceError::OperatorErr, "获取卡片余额失败");
            return false;
        }

        rlt.Put("Balance", ArgConvert::ToString<uint>(balance));
        return true;
    }
    /**
     * @brief 获取IC卡数据
     * @date 2016-05-06 18:17
     * @warning 在获取到标签时,会自动增加GAC所依赖的必选标签
     * 
     * @param [in] AID : hex [default:PBOC] 需要获取的AID
     * @param [in] FLAG : string 需要读取的标签(ABCD),""表示读取全部
     * @warning 如果FLAG标签不存在,则直接以TAG,SubTAG为准读取IC卡信息
     * 
     * @param [in] TAG : hex [default:""] 需要读取的必选标签
     * @param [in] SubTAG : hex [default:""] 需要读取的可选标签
     *
     * @retuan 读取到的数据存放到类中的全局变量AppData中
     */
    LC_CMD_METHOD(GetInformation)
    {
        string sAid = arg["AID"].To<string>();
        ByteBuilder tag(8);
        ByteBuilder subTag(8);

        string sFlag;
        if(arg.Get("FLAG", sFlag))
        {
            PBOC_AppHelper::getTagHeader(sFlag.c_str(), InformationTABLE, tag);
        }
        sFlag = arg["TAG"].To<string>("");
        DevCommand::FromAscii(sFlag.c_str(), tag);
        
        sFlag = arg["SubTAG"].To<string>("");
        DevCommand::FromAscii(sFlag.c_str(), subTag);

        _appData.Clear();
        if(!_icAdapter.GetInformation(DevCommand::FromAscii(sAid.c_str()), tag, subTag, _appData))
        {
            _logErr(DeviceError::OperatorErr, "获取卡片信息失败");
            return false;
        }
        return true;
    }
    /**
     * @brief 获取55域数据
     * @date 2016-06-21 17:51
     * 
     * @param [in] AID : hex [default:PBOC] 需要获取ARQC的AID
     * @param [in] TAG : string [default:Auto] 需要生成55域的标签数据
     * 
     * @retval ARQC : hex 获取到的55域数据 
     * @retval GacType : string GAC类型
     * - 类型:
     *  - AAC
     *  - ARQC
     *  - TC
     *  - Reserve
     * .
     * @retval DOL : hex GAC命令时生成的DOL数据
     */
    LC_CMD_METHOD(GenARQC)
    {
        string sAid = arg["AID"].To<string>();
        ByteBuilder arqc(32);
        ByteBuilder arqcTAG(32);
        string sTag;
        const char* pTag = NULL;
        if(arg.Get("TAG", sTag))
            pTag = sTag.c_str();
        
        GenerateACCmd::RefCtlFlag gacFlag = GenerateACCmd::ARQC;
        ByteBuilder dol(32);
        if(!_icAdapter.GenArqc(_amountData, arqc, _appData, &gacFlag, pTag, &dol))
            return false;
        string sGacType = "Unknown";
        switch(gacFlag)
        {
        case GenerateACCmd::AAC:
            sGacType = "AAC";
            break;
        case GenerateACCmd::ARQC:
            sGacType = "ARQC";
            break;
        case GenerateACCmd::TC:
            sGacType = "TC";
            break;
        case GenerateACCmd::Reserve:
            sGacType = "Reserve";
            break;
        }
        rlt.Put("GacType", sGacType);
        rlt.Put("ARQC", ArgConvert::ToString(arqc));
        rlt.Put("DOL", ArgConvert::ToString(dol));
        return true;
    }
    /**
     * @brief 执行写卡脚本
     * @date 2016-06-21 17:59
     * 
     * @param [in] ARPC : hex 后台返回的写卡脚本
     * @param [in] TAG : hex [default:Auto] 需要生成的TC标签列表
     * @param [in] GacMode : string [default:First] GAC模式
     * - 参数:
     *  - None 不处理GAC
     *  - First GAC于脚本优先
     *  - Normal GAC于脚本之后
     * .
     * 
     * @retval DF31 : hex 写卡脚本通知
     * @retval TC : hex 写卡成功后返回的TC数据
     * @retval DOL : hex 执行GAC时生成的DOL数据
     */
    LC_CMD_METHOD(RunARPC)
    {
        string sArpc = arg["ARPC"].To<string>();
        ByteBuilder arpc(32);
        DevCommand::FromAscii(sArpc.c_str(), arpc);

        string sTag;
        const char* pTag = NULL;
        if(arg.Get("TAG", sTag))
            pTag = sTag.c_str();
        ByteBuilder gac(8);
        ByteBuilder df31(8);
        ByteBuilder tc(32);
        ByteBuilder* pTC = NULL;
        GenerateACCmd::RefCtlFlag gacFlag = GenerateACCmd::TC;
        bool isLogFirst = true;
        bool isNeedTC = true;
        ByteArray sGacMode(arg["GacMode"].To<string>("First").c_str());
        if(StringConvert::Compare(sGacMode, "First", true))
        {
            isLogFirst = false;
            pTC = &tc;
        }
        else if(StringConvert::Compare(sGacMode, "Normal", true))
        {
            pTC = &tc;
        }
        else if(StringConvert::Compare(sGacMode, "None", true))
        {
            isNeedTC = false;
        }
        ByteBuilder dol(32);
        if(!_icAdapter.RunArpc(_amountData, arpc, _appData, df31, pTag, pTC, &gacFlag, isLogFirst, &dol))
            return false;
        if(isNeedTC)
            rlt.Put("TC", ArgConvert::ToString(tc));
        rlt.Put("DF31", ArgConvert::ToString(df31));
        rlt.Put("DOL", ArgConvert::ToString(dol));
        return true;
    }
    /**
     * @brief 获取卡片脱机交易明细
     * @date 2016-06-21 18:02
     * 
     * @param [in] AID : hex [default:PBOC] 需要获取明细的AID
     * @param [in] Index : uint [default:0] 需要获取的明细索引号
     * @warning 为0时表示获取所有交易明细
     * 
     * @retval INFO : string 获取到的交易明细(PQRST)
     * @retval Count : size_t 获取到的交易条数
     */
    LC_CMD_METHOD(GetDetail)
    {
        string sAid = arg["AID"].To<string>();
        uint index = arg["Index"].To<uint>(0);

        ByteBuilder detailFormat(16);
        list_t<ByteBuilder> detailList;

        ByteBuilder aid(8);
        DevCommand::FromAscii(sAid.c_str(), aid);
        if(!_icAdapter.GetDealDetail(detailFormat, detailList, aid, _itobyte(index)))
        {
            _logErr(DeviceError::OperatorErr, "获取日志数据失败");
            return false;
        }

        ByteBuilder detailData(256);
        ByteBuilder detailBuff(256);
        PbocTlvConverter tlvConverter(TlvAnsConvert);
        list_t<ByteBuilder>::iterator itr;
        for(itr = detailList.begin();itr != detailList.end();++itr)
        {
            detailData.Clear();
            PBOC_AppHelper::packFormatData(detailFormat, *itr, detailBuff);
            PBOC_AppHelper::transFromTLV(detailBuff, detailData, 3, "", DetailTABLE, tlvConverter, true);

            rlt.Put("INFO", detailData.GetString());
        }
        rlt.Put("Count", ArgConvert::ToString(detailList.size()));
        return true;
    }
    /**
     * @brief 获取圈存日志
     * @date 2016-10-12 22:39
     *
     * @param [in] AID : hex [default:PBOC] 需要获取明细的AID
     * @param [in] Index : uint [default:0] 需要获取的明细索引号
     * @warning 为0时表示获取所有交易明细
     * 
     * @retval INFO : string 获取到的交易明细(PQRST)
     */
    LC_CMD_METHOD(GetAmtDetail)
    {
        return true;
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_PBOC_CMDDRIVER_H_
//========================================================= 